using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace IUPUI.StellarResults.Client
{
	/// <summary>
	/// A form to edit or create <see cref="Simulation"/>s.
	/// </summary>
	public partial class SimulationEditorForm : Form
	{
		#region Private Properties
		private Simulation m_Simulation = new Simulation();
		private string m_FileName = String.Empty;
		#endregion Private Properties

		#region Public Properties
		/// <summary>
		/// Gets or sets the simulation.
		/// </summary>
		/// <value>The simulation.</value>
		public Simulation Simulation
		{
			get
			{
				return m_Simulation;
			}
			set
			{
				if (m_Simulation != value)
				{
					m_Simulation = value;
					OnSimulationChanged();
				}
			}
		}

		/// <summary>
		/// Gets or sets the name of the file.
		/// </summary>
		/// <value>The name of the file.</value>
		public string FileName
		{
			get
			{
				return m_FileName;
			}
			set
			{
				m_FileName = value;
				OnFileNameChanged();
			}
		}
		#endregion Public Properties

		#region Constructors
		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationEditorForm"/> class.
		/// </summary>
		public SimulationEditorForm()
		{
			InitializeComponent();

			m_SaveFileDialog.DefaultExt =
				Properties.Resources.SimulationFileDefaultExt;
			m_SaveFileDialog.Filter =
				Properties.Resources.SimulationFileFilter;

			OnSimulationChanged();
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationEditorForm"/> class.
		/// </summary>
		public SimulationEditorForm(
			Simulation simulation)
			: this()
		{
			Simulation = simulation;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="SimulationEditorForm"/> class.
		/// </summary>
		public SimulationEditorForm(
			Simulation simulation,
			string fileName)
			: this(simulation)
		{
			FileName = fileName;
		}
		#endregion Constructors

		/// <summary>
		/// Called when [simulation changed].
		/// </summary>
		protected virtual void OnSimulationChanged()
		{
			if (m_Simulation == null)
			{
				m_Simulation = new Simulation();
			}

			if (m_SimulationPropertyGrid.SelectedObject != m_Simulation)
			{
				m_SimulationPropertyGrid.SelectedObject = m_Simulation;
			}
		}

		#region Actions
		/// <summary>
		/// Handles the Click event of the m_CancelButton control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void m_CancelButton_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		/// <summary>
		/// Handles the Click event of the m_SaveAsButton control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void m_SaveAsButton_Click(object sender, EventArgs e)
		{
			SaveAs();
		}

		/// <summary>
		/// Handles the Click event of the m_SaveButton control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
		private void m_SaveButton_Click(object sender, EventArgs e)
		{
			Save();
		}
		#endregion Actions

		/// <summary>
		/// Called when [file name changed].
		/// </summary>
		private void OnFileNameChanged()
		{
			m_SaveButton.Enabled = !String.IsNullOrEmpty(FileName);
		}

		/// <summary>
		/// Validates the simulation.
		/// </summary>
		/// <returns></returns>
		private bool ValidateSimulation()
		{
			List<String> errors = new List<string>();

			foreach (Observatory observatory in m_Simulation.Observatories)
			{
				if (String.IsNullOrEmpty(observatory.ID))
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_CannotBeNullOrEmpty,
							"ID",
							"Observatory"));
				}

				if (String.IsNullOrEmpty(observatory.Name))
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_CannotBeNullOrEmpty,
							"Name",
							"Observatory"));
				}

				if (m_Simulation.Observatories.FindAll(
					delegate(Observatory o)
					{
						return o.ID == observatory.ID;
					}).Count > 1)
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_MustBeUnique,
							"ID",
							"Observatory"));
				}

				if (observatory.Altazimuth.Altitude < 0
					|| observatory.Altazimuth.Altitude > 90)
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_BadRange,
							"Altazimuth",
							"Observatory",
							"0",
							"90"));
				}

				if (observatory.Altazimuth.Azimuth < 0
					|| observatory.Altazimuth.Altitude > 360)
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_BadRange,
							"Altazimuth",
							"Observatory",
							"0",
							"360"));
				}
			}

			foreach (AstronomicalObject astronomicalObject in m_Simulation.AstronomicalObjects)
			{
				if (String.IsNullOrEmpty(astronomicalObject.ID))
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_CannotBeNullOrEmpty,
							"ID",
							"AstronomicalObject"));
				}
				if (String.IsNullOrEmpty(astronomicalObject.Name))
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_CannotBeNullOrEmpty,
							"Name",
							"AstronomicalObject"));
				}

				if (m_Simulation.AstronomicalObjects.FindAll(
					delegate(AstronomicalObject ao)
					{
						return ao.ID == astronomicalObject.ID;
					}).Count > 1)
				{
					errors.Add(
						String.Format(
							Properties.Resources.Validate_MustBeUnique,
							"ID",
							"AstronomicalObject"));
				}
			}

			// If there are any errors, then display them now
			if (errors.Count > 0)
			{
				string errorMessage = Properties.Resources.ValidationErrors;
				for (int i = 0; i < errors.Count; i++)
				{
					errorMessage += String.Format(
						"{0}{1}. {2}",
						System.Environment.NewLine,
						(i + 1).ToString(),
						errors[i]);
				}

				MessageBox.Show(
					this,
					errorMessage,
					Properties.Resources.ErrorTitle,
					MessageBoxButtons.OK,
					MessageBoxIcon.Error);

				return false;
			}
			else
			{
				return true;
			}
		}

		/// <summary>
		/// Saves this instance.
		/// </summary>
		private void Save()
		{
			if (String.IsNullOrEmpty(FileName))
			{
				SaveAs();
				return;
			}

			// Validate the simulation, and save if all is well
			if (ValidateSimulation())
			{
				m_Simulation.LastUpdatedDateTime = DateTime.UtcNow;
				m_Simulation.Version++;

				// If file exists, make sure its not read only
				if (System.IO.File.Exists(FileName))
				{
					System.IO.File.SetAttributes(
						FileName,
						~System.IO.FileAttributes.ReadOnly);
				}

				// Save file
				m_Simulation.Save(FileName);

				this.DialogResult = DialogResult.OK;
			}
		}

		/// <summary>
		/// Saves this instance as.
		/// </summary>
		private void SaveAs()
		{
			if (m_SaveFileDialog.ShowDialog(this) == DialogResult.OK)
			{
				m_Simulation.CreatedDateTime = DateTime.UtcNow;
				// Set version to 0, so it will be set to 1 in Save()
				m_Simulation.Version = 0;

				FileName = m_SaveFileDialog.FileName;

				if (!String.IsNullOrEmpty(FileName))
				{
					Save();
				}
				else
				{
					MessageBox.Show(
						this,
						Properties.Resources.FileNameCannotBeEmpty,
						Properties.Resources.ErrorTitle,
						MessageBoxButtons.OK,
						MessageBoxIcon.Error);
				}
			}
		}
	}
}